/**
 * 预加载脚本 - 安全的 IPC 通信桥梁
 *
 * @fileoverview 该文件是 Electron 预加载脚本，负责在渲染进程和主进程之间建立安全的通信桥梁。
 * 通过 contextBridge 暴露受限的 API，确保渲染进程无法直接访问 Node.js API，同时提供必要的功能接口。
 *
 * 核心功能：
 * - 参数序列化：将 Vue reactive/Proxy 对象转换为可克隆的纯数据
 * - 安全封装：统一封装所有 IPC 调用，防止结构化克隆失败
 * - 类型安全：提供完整的 TypeScript 类型定义
 * - 错误处理：包含克隆失败的回退机制
 *
 * @author System
 * @version 1.0.0
 * @since 2024
 */

import type {
  AppointmentsExportRequest,
  AppointmentsExportResponse,
  AppointmentsListRequest,
  AppointmentsListResponse,
  AvailabilityCheckRequest,
  AvailabilityCheckResponse,
  ConfigGetRequest,
  ConfigGetResponse,
  ConfigSetRequest,
  ConfigSetResponse,
  LogEvent,
  LogGetFilesRequest,
  LogGetFilesResponse,
  LogSubscribeRequest,
  ScriptRunRequest,
  ScriptRunResponse,
  ScriptStatusRequest,
  ScriptStatusResponse,
  ScriptStopRequest,
  ScriptStopResponse,
} from '@shared/types/ipc'
import process from 'node:process'
import { contextBridge, ipcRenderer } from 'electron'

/**
 * 将参数转换为可通过结构化克隆的纯数据
 *
 * @description 该函数专门处理 Vue reactive/Proxy 对象、函数、符号等无法被结构化克隆算法处理的数据类型，
 * 将它们转换为可以安全传递给主进程的纯数据。这是解决 "An object could not be cloned" 错误的核心函数。
 *
 * @param {any} value - 需要转换的值，可以是任意类型
 * @returns {any} 转换后的可克隆数据，无法转换的返回 undefined
 *
 * @example
 * // Vue reactive 对象
 * const reactiveData = reactive({ name: 'John', age: 30 })
 * const plain = toPlainSerializable(reactiveData) // { name: 'John', age: 30 }
 *
 * // 包含函数的对象
 * const obj = { data: 'test', fn: () => {} }
 * const plain = toPlainSerializable(obj) // { data: 'test' }
 *
 * // 日期对象
 * const date = new Date()
 * const plain = toPlainSerializable(date) // "2024-01-01T00:00:00.000Z"
 */
function toPlainSerializable(value: any): any {
  // 处理原始类型与 null/undefined
  if (value === null || value === undefined)
    return value

  const type = typeof value

  // 原始类型直接返回
  if (type === 'string' || type === 'number' || type === 'boolean')
    return value

  // BigInt 转为普通数字（可能精度丢失，但可克隆）
  if (type === 'bigint')
    return Number(value)

  // 函数和符号无法克隆，返回 undefined（后续会被过滤）
  if (type === 'function' || type === 'symbol')
    return undefined

  // 日期对象转为 ISO 字符串
  if (value instanceof Date)
    return value.toISOString()

  // Buffer/TypedArray/ArrayBuffer 可以被结构化克隆算法直接处理
  if (typeof ArrayBuffer !== 'undefined') {
    const AB: any = ArrayBuffer as any
    if (value instanceof ArrayBuffer)
      return value
    if (AB.isView && AB.isView(value))
      return value
  }

  // 数组：递归处理每个元素，过滤掉 undefined 值
  if (Array.isArray(value))
    return value.map(v => toPlainSerializable(v)).filter(v => v !== undefined)

  // 普通对象处理（包括 Vue reactive/proxy 对象）
  try {
    const plain: Record<string, any> = {}
    // 遍历对象的可枚举属性（会自动解开 Proxy）
    for (const key of Object.keys(value)) {
      const v = toPlainSerializable((value as any)[key])
      if (v !== undefined)
        plain[key] = v
    }
    return plain
  }
  catch {
    // 第一层回退：尝试 JSON 序列化/反序列化
    try {
      return JSON.parse(JSON.stringify(value))
    }
    catch {
      // 最终回退：返回 undefined
      return undefined
    }
  }
}

/**
 * 安全的 IPC 调用封装函数
 *
 * @description 统一封装所有 ipcRenderer.invoke 调用，自动处理参数序列化和克隆失败的回退机制。
 * 这是防止 "An object could not be cloned" 错误的最后一道防线。
 *
 * @param {string} channel - IPC 通道名称
 * @param {...any[]} args - 传递给主进程的参数列表
 * @returns {Promise<any>} 主进程的响应结果
 *
 * @throws {Error} 当所有回退机制都失败时，抛出原始错误
 *
 * @example
 * // 基本用法
 * const result = await safeInvoke('appointment:create', appointmentData)
 *
 * // 带多个参数
 * const result = await safeInvoke('appointment:update', id, updateData)
 *
 * @see {@link toPlainSerializable} 参数序列化函数
 */
function safeInvoke(channel: string, ...args: any[]): Promise<any> {
  // 第一步：使用自定义序列化函数清洗所有参数
  const sanitized = args.map(a => toPlainSerializable(a))
  let invoked: Promise<any>

  try {
    // 第二步：尝试调用 IPC
    invoked = ipcRenderer.invoke(channel, ...sanitized)
  }
  catch (err: any) {
    // 第三步：同步阶段捕获克隆失败，使用严格 JSON 序列化回退
    if (err && /could not be cloned/i.test(String(err?.message || err))) {
      const strictPlain = JSON.parse(JSON.stringify(sanitized))
      return ipcRenderer.invoke(channel, ...strictPlain)
    }
    throw err
  }

  // 第四步：异步阶段捕获克隆失败（主进程处理前），再次回退
  return invoked.catch((err: any) => {
    if (err && /could not be cloned/i.test(String(err?.message || err))) {
      const strictPlain = JSON.parse(JSON.stringify(sanitized))
      return ipcRenderer.invoke(channel, ...strictPlain)
    }
    throw err
  })
}

/**
 * 渲染进程可用的 API 接口定义
 *
 * @description 通过 contextBridge 暴露给渲染进程的安全 API 集合。
 * 所有方法都通过 safeInvoke 封装，确保参数可以安全地传递给主进程。
 *
 * @namespace api
 */
const api = {
  /**
   * 脚本执行模块
   * @namespace api.script
   */
  script: {
    /** 运行自动化脚本 */
    run: (request: ScriptRunRequest): Promise<ScriptRunResponse> =>
      safeInvoke('script:run', request),
    /** 停止正在运行的脚本 */
    stop: (request: ScriptStopRequest): Promise<ScriptStopResponse> =>
      safeInvoke('script:stop', request),
    /** 获取脚本运行状态 */
    status: (request: ScriptStatusRequest): Promise<ScriptStatusResponse> =>
      safeInvoke('script:status', request),
    /** 清理历史任务记录 */
    clear: (request: { keep_running?: boolean, older_than?: number }): Promise<{ success: boolean, deleted_count: number, error?: string }> =>
      safeInvoke('script:clear', request),
  },

  /**
   * 可用性查询模块
   * @namespace api.availability
   */
  availability: {
    /** 检查预约时段可用性 */
    check: (request: AvailabilityCheckRequest): Promise<AvailabilityCheckResponse> =>
      safeInvoke('availability:check', request),
  },

  /**
   * 配置管理模块
   * @namespace api.config
   */
  config: {
    /** 获取配置项 */
    get: (request: ConfigGetRequest): Promise<ConfigGetResponse> =>
      safeInvoke('config:get', request),
    /** 设置配置项 */
    set: (request: ConfigSetRequest): Promise<ConfigSetResponse> =>
      safeInvoke('config:set', request),
    /** 重置配置到默认值 */
    reset: (): Promise<any> =>
      safeInvoke('config:reset'),
    /** 验证配置是否有效 */
    validate: (config: any): Promise<any> =>
      safeInvoke('config:validate', config),
    /** 获取所有配置项 */
    list: (options?: any): Promise<any> =>
      safeInvoke('config:list', options),
    /** 创建配置项 */
    create: (request: any): Promise<any> =>
      safeInvoke('config:create', request),
    /** 更新配置项 */
    update: (request: any): Promise<any> =>
      safeInvoke('config:update', request),
    /** 删除配置项 */
    delete: (request: any): Promise<any> =>
      safeInvoke('config:delete', request),
  },

  /**
   * 代理操作模块
   * @namespace api.proxy
   */
  proxy: {
    /** 手动校验所有启用的代理池，失败写入临时黑名单 */
    validatePool: (): Promise<any> =>
      safeInvoke('proxy:validate-pool'),
    /** 获取临时黑名单（会自动清理过期项） */
    blacklistList: (): Promise<any> =>
      safeInvoke('proxy:blacklist:list'),
    /** 清空临时黑名单 */
    blacklistClear: (): Promise<any> =>
      safeInvoke('proxy:blacklist:clear'),
    /** 通过 WebShare API 列表拉取指定 provider 的代理池 */
    websharePullList: (providerId: string): Promise<any> =>
      safeInvoke('proxy:webshare:pull-list', { provider_id: providerId }),
    /** 代理测试：对指定URL做连通性检查并返回出口IP */
    testUrl: (url: string, providerId?: string): Promise<any> =>
      safeInvoke('proxy:test-url', { url, provider_id: providerId }),
    /** 列出本月超额标记 */
    quotaList: (): Promise<any> =>
      safeInvoke('proxy:quota:list'),
    /** 标记某 provider 本月为超额 */
    quotaMark: (providerId: string, reason?: string): Promise<any> =>
      safeInvoke('proxy:quota:mark', { provider_id: providerId, reason }),
    /** 清除某 provider 的（指定或当前月）超额标记 */
    quotaClear: (providerId: string, month?: string): Promise<any> =>
      safeInvoke('proxy:quota:clear', { provider_id: providerId, month }),
    /** 查询 WebShare 订阅/区间的聚合用量（bandwidth_total、requests_* 等） */
    webshareStatsAggregate: (providerId: string, opts?: { plan_id?: string, gte?: string, lte?: string }): Promise<any> =>
      safeInvoke('proxy:webshare:stats-aggregate', { provider_id: providerId, plan_id: opts?.plan_id, gte: opts?.gte, lte: opts?.lte }),
  },

  /**
   * 预约管理模块
   * @namespace api.appointment
   */
  appointment: {
    /** 创建预约记录 */
    create: (input: any): Promise<any> =>
      safeInvoke('appointment:create', input),
    /** 获取单个预约记录 */
    get: (id: number): Promise<any> =>
      safeInvoke('appointment:get', id),
    /** 更新预约记录 */
    update: (id: number, input: any): Promise<any> =>
      safeInvoke('appointment:update', id, input),
    /** 删除预约记录 */
    delete: (id: number): Promise<any> =>
      safeInvoke('appointment:delete', id),
    /** 查询预约记录列表 */
    list: (filters: any, pagination: any): Promise<any> =>
      safeInvoke('appointment:list', filters, pagination),
    /** 批量操作预约记录 */
    batchOperation: (request: any): Promise<any> =>
      safeInvoke('appointment:batch-operation', request),
    /** 获取预约统计信息 */
    statistics: (): Promise<any> =>
      safeInvoke('appointment:statistics'),
    /** 获取预约操作日志 */
    operationLogs: (appointmentId: number): Promise<any> =>
      safeInvoke('appointment:operation-logs', appointmentId),

    /** 订阅预约更新事件（主进程广播的实时更新） */
    onUpdated: (handler: (payload: any) => void): (() => void) => {
      const listener = (_event: any, payload: any) => {
        try { handler(payload) }
        catch {}
      }
      ipcRenderer.on('appointment:updated', listener)
      return () => {
        try { ipcRenderer.removeListener('appointment:updated', listener) }
        catch {}
      }
    },
  },

  /**
   * Excel 导入导出模块
   * @namespace api.excel
   */
  excel: {
    /** 从 Excel 文件导入预约数据 */
    import: (filePath: string): Promise<any> =>
      safeInvoke('excel:import', filePath),
    /** 生成 Excel 模板文件 */
    generateTemplate: (): Promise<any> =>
      safeInvoke('excel:generate-template'),
    /** 导出预约数据到 Excel */
    export: (appointmentIds?: number[]): Promise<any> =>
      safeInvoke('excel:export', appointmentIds),
    /** 按筛选条件导出预约数据到 Excel */
    exportByFilters: (filters: any): Promise<any> =>
      safeInvoke('excel:export-by-filters', filters),
  },

  /**
   * 远程网站请求模块（查询/更改/取消）
   * @namespace api.remote
   */
  remote: {
    /** 按参考编号后6位查询预约信息 */
    queryByRef: (refLast6: string): Promise<any> =>
      safeInvoke('remote-appointment:query-by-ref', refLast6),
    /** 按证件/执照查询预约信息 */
    queryById: (payload: { passport?: string, hkid?: string, license?: string }): Promise<any> =>
      safeInvoke('remote-appointment:query-by-id', payload),
    /** 按参考编号后6位取消预约 */
    cancelByRef: (refLast6: string): Promise<any> =>
      safeInvoke('remote-appointment:cancel-by-ref', refLast6),
    /** 更改预约时间段（需参考号后6位） */
    updateTimeslot: (payload: { refLast6: string, officeCode?: string, preferredDates?: string[], preferredTimes?: string[] }): Promise<any> =>
      safeInvoke('remote-appointment:update-timeslot', payload),
    /** 批量取消（参考号后6位数组，可配置并发/重试/验证） */
    batchCancel: (
      refs: string[],
      options?: { concurrency?: number, retries?: number, retryDelayMs?: number, verify?: boolean, verifyDelayMs?: number },
    ): Promise<any> =>
      safeInvoke('remote-appointment:batch-cancel', refs, options),
  },

  /**
   * 新预约接口（两种模式：playwright/request）
   * @namespace api.booking
   */
  booking: {
    /** 执行预约 */
    book: (payload: { mode: 'playwright' | 'request', appointment: any, options?: any }): Promise<any> =>
      safeInvoke('booking:book', payload),
    /** 批量预约（并发） */
    bookMultiple: (payload: { mode: 'playwright' | 'request', appointments: any[], options?: any, concurrency?: number, persist?: boolean }): Promise<any> =>
      safeInvoke('booking:book-multiple', payload),
    /** 停止当前所有预约 */
    stop: (): Promise<any> => safeInvoke('booking:stop'),
    /** 启动监控优先策略（先探测可约再并发） */
    monitorStart: (payload: { monitor: any, candidates: any[], concurrency: number, intervalMs?: number, windowDays?: number, options?: any }): Promise<any> =>
      safeInvoke('booking-monitor:start', payload),
    /** 停止监控 */
    monitorStop: (): Promise<any> => safeInvoke('booking-monitor:stop'),
    /** 修复缺失的预约数据（参考编号、预约日期、预约时间） */
    repairMissingData: (): Promise<{ success: boolean, repaired: number, skipped: number, failed: number, total: number, message: string, error?: string }> =>
      safeInvoke('booking:repair-missing-data'),
  },

  /**
   * 文件对话框模块
   * @namespace api.dialog
   */
  dialog: {
    /** 打开文件选择对话框 */
    openFile: (options: any): Promise<any> =>
      safeInvoke('dialog:open-file', options),
    /** 打开文件保存对话框 */
    saveFile: (options: any): Promise<any> =>
      safeInvoke('dialog:save-file', options),
  },

  /**
   * 占号数据管理模块
   * @namespace api.placeholder
   */
  placeholder: {
    /** 生成单个占号数据 */
    generateSingle: (options: any): Promise<any> =>
      safeInvoke('placeholder:generate-single', options),
    /** 批量生成占号数据 */
    generateBatch: (options: any): Promise<any> =>
      safeInvoke('placeholder:generate-batch', options),
    /** 为指定预约生成占号数据 */
    generateForAppointment: (appointmentId: number, count: number): Promise<any> =>
      safeInvoke('placeholder:generate-for-appointment', appointmentId, count),
    /** 获取占号数据统计信息 */
    statistics: (): Promise<any> =>
      safeInvoke('placeholder:statistics'),
    /** 清理指定的占号数据 */
    cleanupByIds: (placeholderIds: number[]): Promise<any> =>
      safeInvoke('placeholder:cleanup-by-ids', placeholderIds),
    /** 释放指定的占号数据 */
    releaseByIds: (placeholderIds: number[]): Promise<any> =>
      safeInvoke('placeholder:release-by-ids', placeholderIds),
  },

  /**
   * 数据库操作模块（兼容性接口）
   * @namespace api.db
   * @deprecated 建议使用 appointment 模块的相应方法
   */
  db: {
    appointments: {
      /** 查询预约记录列表（兼容性接口） */
      list: (request: AppointmentsListRequest): Promise<AppointmentsListResponse> =>
        safeInvoke('db:appointments:list', request),
      /** 导出预约记录（兼容性接口） */
      export: (request: AppointmentsExportRequest): Promise<AppointmentsExportResponse> =>
        safeInvoke('db:appointments:export', request),
      /** 创建预约记录（兼容性接口） */
      create: (appointment: any): Promise<any> =>
        safeInvoke('db:appointments:create', appointment),
      /** 更新预约记录（兼容性接口） */
      update: (id: number, updates: any): Promise<any> =>
        safeInvoke('db:appointments:update', id, updates),
      /** 删除预约记录（兼容性接口） */
      delete: (id: number): Promise<any> =>
        safeInvoke('db:appointments:delete', id),
    },
  },

  /**
   * 日志管理模块
   * @namespace api.log
   */
  log: {
    /** 订阅日志事件 */
    subscribe: (request: LogSubscribeRequest): Promise<any> =>
      safeInvoke('log:subscribe', request),
    /** 取消日志事件订阅 */
    unsubscribe: (): Promise<any> =>
      safeInvoke('log:unsubscribe'),
    /** 获取日志文件列表 */
    getFiles: (request: LogGetFilesRequest): Promise<LogGetFilesResponse> =>
      safeInvoke('log:get-files', request),
    /** 读取日志文件内容 */
    readFile: (filePath: string, options?: any): Promise<any> =>
      safeInvoke('log:read-file', filePath, options),
    /** 监听日志事件（不通过 safeInvoke，直接使用 IPC 事件） */
    onEvent: (callback: (event: LogEvent) => void): (() => void) => {
      const handler = (_: any, event: LogEvent) => callback(event)
      ipcRenderer.on('log:event', handler)
      return () => ipcRenderer.removeListener('log:event', handler)
    },
  },

  /**
   * 系统操作模块
   * @namespace api.system
   */
  system: {
    /** 使用默认程序打开文件或目录 */
    openPath: (path: string): Promise<any> =>
      safeInvoke('system:open-path', path),
    /** 在文件管理器中显示文件或目录 */
    showInFolder: (path: string): Promise<any> =>
      safeInvoke('system:show-in-folder', path),
    /** 获取应用程序信息 */
    getAppInfo: (): Promise<any> =>
      safeInvoke('system:app-info'),
    /** 获取日志目录路径 */
    getLogsPath: (): Promise<{ success: boolean, path?: string, error?: string }> =>
      safeInvoke('system:get-logs-path'),
    /** 触发 Windows 通知（带动作） */
    notifyAvailable: (title: string, body: string): Promise<any> =>
      safeInvoke('notify:available', { title, body }),
    /** 任务栏关注（闪烁/覆盖图标/托盘红点） */
    attention: (on: boolean, tip?: string): Promise<any> =>
      safeInvoke('system:attention', on, tip),
  },

  /**
   * 自动化预约模块
   * @namespace api.automation
   */
  automation: {
    /** 启动自动化预约流程 */
    start: (request: any): Promise<any> =>
      safeInvoke('automation:start', request),
    /** 停止自动化预约流程 */
    stop: (): Promise<any> =>
      safeInvoke('automation:stop'),
    /** 获取自动化预约状态 */
    status: (): Promise<any> =>
      safeInvoke('automation:status'),
    /** 监听自动化预约日志（不通过 safeInvoke，直接使用 IPC 事件） */
    onLog: (callback: (level: string, message: string) => void): (() => void) => {
      const handler = (_: any, level: string, message: string) => callback(level, message)
      ipcRenderer.on('automation:log', handler)
      return () => ipcRenderer.removeListener('automation:log', handler)
    },
  },

  /**
   * 开发工具模块
   * @namespace api.dev
   */
  dev: {
    /** 打开开发者工具（仅开发模式） */
    openDevTools: (): void => {
      if (process.env.NODE_ENV === 'development') {
        ipcRenderer.send('dev:open-devtools')
      }
    },
    /** 重新加载页面（仅开发模式） */
    reload: (): void => {
      if (process.env.NODE_ENV === 'development') {
        ipcRenderer.send('dev:reload')
      }
    },
  },
}

/**
 * 通过 contextBridge 安全地暴露 API 到渲染进程
 *
 * @description 这是 Electron 安全机制的核心，通过 contextBridge 暴露受控的 API，
 * 避免渲染进程直接访问 Node.js API，同时提供必要的功能接口。
 */
contextBridge.exposeInMainWorld('api', api)

/**
 * TypeScript 全局类型声明
 *
 * @description 扩展 Window 接口，为渲染进程提供类型支持
 */
declare global {
  interface Window {
    /** 主要的 API 接口 */
    api: typeof api
    /** 开发模式下的调试工具 */
    dev?: any
  }
}

/**
 * 预加载 API 类型导出
 *
 * @description 供渲染进程的 TypeScript 代码引用，提供完整的类型支持
 */
export type PreloadApi = typeof api

// ============================================================================
// 开发模式功能
// ============================================================================

/**
 * 开发模式下的额外功能
 *
 * @description 仅在开发环境中启用的调试工具和监控功能
 */
if (process.env.NODE_ENV === 'development') {
  /**
   * 暴露开发调试工具
   */
  contextBridge.exposeInMainWorld('dev', {
    versions: process.versions,
    platform: process.platform,
    arch: process.arch,
    env: process.env.NODE_ENV,
  })

  /**
   * 开发模式启动日志
   */
  window.addEventListener('DOMContentLoaded', () => {
    console.log('🚀 预加载脚本已加载')
    console.log('📦 可用 API:', Object.keys(api))

    if (window.dev) {
      console.log('🛠️ 开发模式已启用')
      console.log('🔧 开发工具:', window.dev)
    }
  })
}

// ============================================================================
// 全局错误处理
// ============================================================================

/**
 * 渲染进程错误监听
 *
 * @description 捕获渲染进程中未被处理的 JavaScript 错误
 */
window.addEventListener('error', (event) => {
  console.error('渲染进程错误:', event.error)
})

/**
 * 未处理的 Promise 拒绝监听
 *
 * @description 捕获渲染进程中未被处理的 Promise 拒绝
 */
window.addEventListener('unhandledrejection', (event) => {
  console.error('未处理的 Promise 拒绝:', event.reason)
})

// ============================================================================
// 性能监控（开发模式）
// ============================================================================

/**
 * 页面加载性能监控
 *
 * @description 仅在开发模式下监控页面加载时间
 */
if (process.env.NODE_ENV === 'development') {
  window.addEventListener('load', () => {
    const loadTime = performance.now()
    console.log(`⏱️ 页面加载时间: ${loadTime.toFixed(2)}ms`)
  })
}
